/**
 * Una instancia "drep" se encarga de ser uno de los repositorios del
 * sistema; se encarga de reportar archivos guardados en su directorio
 * de repositorio, dar informaciones acerca de este y a su vez recibir
 * los archivos que los procesos dcli les envíen. Si se solicita que
 * se use cierto directorio de repositorio y este no existe, DRep lo
 * creará. A su vez drep se comunica con un programa dmon para 
 * reportar sus acciones y actividades, de manera de consultar
 * informaciones solicitadas por programas "dcli".
 *
 * @author Colmenares Carlos (06-39380)
 * @author Tough Alex (07-41604)
 */
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

class DRep {

    public static void main(String[] args){

        //Primero se deben parsear los argumentos,
        //los siguientes son valores de default para
        //estos:
        int puertoDrep = 0;
        String hostDmon = null;
        int puertoDmon = 0;
        String directorioDrep = null;
        boolean verboso = false;

        try {

            int i = 0;
            while( i < args.length ){

                if( args[i].equals("-c") && i+1<args.length ){
                    puertoDrep = Integer.parseInt(args[++i].trim());
                }
                else if( args[i].equals("-h") && i+1<args.length ){
                    hostDmon = args[++i];
                }
                else if( args[i].equals("-p") && i+1<args.length ){
                    puertoDmon = Integer.parseInt(args[++i]);
                }
                else if( args[i].equals("-d") && i+1<args.length ){
                    directorioDrep = args[++i];
                }
                else if( args[i].equals("-v") ){
                    verboso = true;
                }
                else { //( args[i].equals("--help") )
                    imprimirUso();
                }
                i++;
            }
            if( puertoDmon == 0 || hostDmon == null || puertoDrep == 0
                || directorioDrep == null )
                imprimirUso();
            if( puertoDrep > 65535 || puertoDmon > 65535 ){
                System.out.println("Error, ingrese números de puerto válidos");
                System.exit(-1);
            }

        }
        catch(NumberFormatException nfe){
            System.err.println("Error obteniendo número de puertos, por "+
                    "favor indique números enteros");
            System.exit(1);
        }

        //Tratar de abrir el directorio en donde se operará,
        //de no existir, crearlo.
        File repositorio = new File(directorioDrep);
        if(!repositorio.isDirectory()){
            System.out.println("Creando el directorio repositorio: "
                    +directorioDrep);
            repositorio.mkdir();
        }
        if(!repositorio.canRead()){
            System.err.println("Error, no se puede leer el directorio "
                    +"repositorio: "+directorioDrep);
            System.exit(1);
        }

        //Conectarse con el DMon, de fallar, abortar
        Socket dmonSocket = null;
        BufferedReader dmonIn = null;
        PrintWriter dmonOut = null;
        System.out.println("Conectándose con el servidor DMon, esto puede tomar algunos segundos");
        try{
            dmonSocket = new Socket(hostDmon,puertoDmon);
            dmonIn = new BufferedReader(
                    new InputStreamReader(
                        dmonSocket.getInputStream())); 
            dmonOut = new PrintWriter(
                    dmonSocket.getOutputStream(), true);

            dmonOut.println(ProtocoloDMon.CONNECT);
            String resp = dmonIn.readLine();

            if(!resp.equals(ProtocoloDMon.OK)){
                dmonSocket.close();
                throw new IOException("Error de protocolo DMon");
            }

            System.out.println("Se ha conectado con el servidor DMon!");

        } catch (IOException e) {
            System.err.println("Error, no se pudo conectar al DMon en la direción: "
                    +hostDmon+":"+puertoDmon);
            System.err.println(e);
            System.exit(-1);
        }

        //Abrir el socket y esperar por conexiones
        ServerSocket socketServidor = null;

        System.out.println("Iniciando la conexión del servidor drep, "+
                "esto puede tomar unos segundos...");
        try {
            socketServidor = new ServerSocket(puertoDrep);
        } catch (IOException e) {
            System.err.println("Error, no se pudo abrir el socket "+puertoDrep);
            System.err.println(e);
            System.exit(-1);
        }

        //Crear un thread para atender al creador de este proceso
        //por la consola
        new HiloDRep(repositorio,verboso,dmonIn,dmonOut).start();

        //Esperar por conexiones de clientes, al recibirlas,
        //crear un hilo que las atienda y seguir esperando
        //conexiones
        try {

            while(true){

                Socket socketCliente = null;
                socketCliente = socketServidor.accept();

                new HiloDRep(socketCliente, repositorio, verboso,dmonIn,dmonOut).start();
            }

        } catch (IOException e) {
            System.err.println("Error aceptando conexiones");
            System.err.println(e);
            System.exit(1);
        } finally{
            try{
                socketServidor.close();
            }
            catch(Exception e) {
                System.err.println(e);
            }
        }
    }

    /**
     * Esta función imprime los flags que se deben proporcionar
     * al programa para su correto funcionamiento
     */
    private static void imprimirUso(){
        String mnsjError =
            "uso: drep -c <puerto_local_clientes> -h "+
            "<host de dmon> -p <puerto dmon> -d <rdirectorio> "+
            "[-v]";
        System.out.println(mnsjError);
        System.exit(1);
    }
}
